package com.merry.BeanDefinition;

import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.core.AttributeAccessor;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

/**
 * 一个 BeanDefinition 对象描述了一个bean实例。包含了这个实例属性值、构造方法、更进一步的信息（比如，作用域、是否懒加载、父类信息等）。
 *
 * 这个接口只是一个最小的接口，主要目的是允许一个 {@link BeanFactoryPostProcessor} 的实现类
 * 去反射和修改属性值和一些其他的bean的元数据信息。
 * 相关的实现类见：
 * @see ConfigurableListableBeanFactory#getBeanDefinition
 * @see org.springframework.beans.factory.support.RootBeanDefinition
 * @see org.springframework.beans.factory.support.ChildBeanDefinition
 */
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    /**
     * 用来表示当前的bean是一个单例bean。
     * ps：扩展的bean工厂可能支持更多的范围。比如Web相关的bean工厂。
     * @see #setScope
     * @see ConfigurableBeanFactory#SCOPE_SINGLETON
     */
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    /**
     * 用来表示当前bean是一个原型链的bean。
     * @see #setScope
     * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
     */
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


    /**
     * bean的角色：这个值表示当前bean是Spring容器中的主要部分。通常与用户定义的bean有关。
     */
    int ROLE_APPLICATION = 0;

    /**
     * bean的角色：这个值表示当前的bean是Spring容器中的一个较大配置的支持部分。
     * 通常是一个外部的bean {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
     * 作用暂时不懂！
     */
    int ROLE_SUPPORT = 1;

    /**
     * 这个值表示，当前bean是Spring的一个内部bean，提供的一个背景角色的作用，与用户无关，
     *  这个bean的注册与内部有关。 {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
     */
    int ROLE_INFRASTRUCTURE = 2;


    // 可以修改的属性。

    /**
     * 设置beanDefinition的父BeanDefinition对象是什么，如果有的话。
     * 在XML配置中，有一个parent属性指定，在注解的方式中，如果A和B存在继承关系，并且A和B都交给Spring管理，那么这个值就存在。
     */
    void setParentName(@Nullable String parentName);

    /**
     * 返回当前BeanDefinition的父BeanDefinition
     */
    @Nullable
    String getParentName();

    /**
     * 指定当前Bean的className是什么，在 {BeanPostProcessor} 的 post-processing 方法中可以进行修改。
     * 通常用解析后的类名变体替换原始类名。
     * @see #setParentName
     * @see #setFactoryBeanName
     * @see #setFactoryMethodName
     */
    void setBeanClassName(@Nullable String beanClassName);

    /**
     * 返回当前BeanDefinition中的bean的className，
     * 注意：如果子类覆盖/继承了父类的类名，则这不一定是运行时使用的实际类名。
     * 此外，这可能只是调用工厂方法的类，或者在调用方法的工厂bean引用的情况下，它甚至可能是空的。
     * 因此，不要将其视为运行时的最终bean类型，而只将其用于单个bean定义级别的解析目的。
     * @see #getParentName()
     * @see #getFactoryBeanName()
     * @see #getFactoryMethodName()
     */
    @Nullable
    String getBeanClassName();

    /**
     * 重写Bean的Scope，指定一个新的scope名称
     * @see #SCOPE_SINGLETON
     * @see #SCOPE_PROTOTYPE
     */
    void setScope(@Nullable String scope);

    /**
     * 返回当前bean的scope名称。可能返回null（在不知道的情况下）。
     */
    @Nullable
    String getScope();

    /**
     * 指定当前bean是不是一个懒加载的bean。
     * 如果 {@code false}，则会在spring容器初始化的时候加载所有的【单例】bean。
     */
    void setLazyInit(boolean lazyInit);

    /**
     * 返回当前bean是不是一个懒加载的bean，注意这个方法只适用于单例bean。
     */
    boolean isLazyInit();

    /**
     * 设置当前bean初始化时，需要依赖的其他bean。
     * spring会优先保证依赖的bean先加载。
     */
    void setDependsOn(@Nullable String... dependsOn);

    /**
     * 获取当前bean所依赖的其他bean。
     */
    @Nullable
    String[] getDependsOn();

    /**
     * 设置当前bean是否可以被 {@link org.springframework.beans.factory.annotation.Autowired} 等注解注入到其他的bean中。
     * 注意：这个属性仅仅影响基于类型 {type-based} 的注入，也就是说它不影响基于名称 {by-named} 的注入
     * {@link javax.annotation.Resource}
     */
    void setAutowireCandidate(boolean autowireCandidate);

    /**
     * 返回这个bean是否被注入。
     */
    boolean isAutowireCandidate();

    /**
     * 如果自动注入的时候匹配到了多个同类型 {by-typed} 的bean。
     * 那么这个值为 {@code true} 的将会被选中。
     */
    void setPrimary(boolean primary);

    /**
     * {@see primary}
     */
    boolean isPrimary();

    /**
     * 如果有的话，指定这个bean的factoryBean的信息。
     * 这是通过工厂方法获取bean的名称。
     * @see #setFactoryMethodName
     */
    void setFactoryBeanName(@Nullable String factoryBeanName);

    /**
     * 返回当前bean的FactoryBean，如果有的话。
     */
    @Nullable
    String getFactoryBeanName();

    /**
     * 指定一个工厂方法（如果有的话），
     *  1.此方法将使用构造函数参数调用，如果没有指定参数，则不使用参数调用。
     *  2.该方法将在指定的工厂bean上调用（如果有的话）。
     *  3.否则将作为本地bean类上的静态方法调用。
     * @see #setFactoryBeanName
     * @see #setBeanClassName
     */
    void setFactoryMethodName(@Nullable String factoryMethodName);

    /**
     * 返回一个工厂方法，如果有的话。
     */
    @Nullable
    String getFactoryMethodName();

    /**
     * 返回这个bean的一个构造方法的参数值。
     * 返回的值可以在 {BeanPostProcessor} 的 post-processing 方法中被修改。
     */
    ConstructorArgumentValues getConstructorArgumentValues();

    /**
     * 如果为此bean定义了构造函数参数值，则返回。
     * @since 5.0.2
     */
    default boolean hasConstructorArgumentValues() {
        return !getConstructorArgumentValues().isEmpty();
    }

    /**
     * 返回要应用于bean新实例的属性值。
     * 返回的值可以在 {BeanPostProcessor} 的 post-processing 方法中被修改。
     */
    MutablePropertyValues getPropertyValues();

    default boolean hasPropertyValues() {
        return !getPropertyValues().isEmpty();
    }

    /**
     * 设置当前bean的 {init-method} 方法。
     * 这个方法会在创建实例化之后被执行。
     * @since 5.1
     */
    void setInitMethodName(@Nullable String initMethodName);

    /**
     * @since 5.1
     */
    @Nullable
    String getInitMethodName();

    /**
     * 设置当前bean的 {destroy-method} 方法。
     * 这个方法会在bean创建完成之后被设置，并且会在bean销毁的时候触发 {destroy-method}
     * @since 5.1
     */
    void setDestroyMethodName(@Nullable String destroyMethodName);

    /**
     * @since 5.1
     */
    @Nullable
    String getDestroyMethodName();

    /**
     * 设置 {BeanDefinition} 的角色，这个角色为 【框架和工具】 指明了当前 {bean} 的一部分作用。
     * @see #ROLE_APPLICATION
     * @see #ROLE_SUPPORT
     * @see #ROLE_INFRASTRUCTURE
     */
    void setRole(int role);

    /**
     * 获取当前bean的角色。
     * @see #ROLE_APPLICATION
     * @see #ROLE_SUPPORT
     * @see #ROLE_INFRASTRUCTURE
     */
    int getRole();

    /**
     * 为当前bean设置一个说人话的描述。
     * @since 5.1
     */
    void setDescription(@Nullable String description);

    @Nullable
    String getDescription();

    // 只读属性

    /**
     *  根据bean或其他特定元数据，返回此beanDefinition的可解析类型。
     *  这通常在运行时在合并的beanDefinition上完全解决，但不一定在配置时解决
     * @since 5.2
     * @see ConfigurableBeanFactory#getMergedBeanDefinition
     */
    ResolvableType getResolvableType();

    /**
     * 返回当前bean是否为单例bean。
     * @see #SCOPE_SINGLETON
     */
    boolean isSingleton();

    /**
     * 返回当前bean是否为 原型链的bean。
     * @see #SCOPE_PROTOTYPE
     */
    boolean isPrototype();

    /**
     * 返回当前bean是否为一个 {abstract} 抽象类，如果是抽象类，则意味着它不能被实例化。
     */
    boolean isAbstract();

    /**
     * 返回这个beanDefinition资源的描述符，为了在【出现错误时显示上下文】
     */
    @Nullable
    String getResourceDescription();

    /**
     * 返回这个bean的原始的BeanDefinition对象。
     */
    @Nullable
    BeanDefinition getOriginatingBeanDefinition();

}

